package com.zbkj.front.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.zbkj.common.config.BaseConfig;
import com.zbkj.common.constants.Constants;
import com.zbkj.common.enums.*;
import com.zbkj.common.exception.CommonException;
import com.zbkj.common.exception.ExceptionCodeEnum;
import com.zbkj.common.exception.ResultException;
import com.zbkj.common.model.project.*;
import com.zbkj.common.model.standard.PeProjectStandard;
import com.zbkj.common.model.user.User;
import com.zbkj.common.model.user.UserBill;
import com.zbkj.common.oss.OssClientUtil;
import com.zbkj.common.page.CommonPage;
import com.zbkj.common.request.enquiry.ReportRequest;
import com.zbkj.common.request.project.*;
import com.zbkj.common.request.standard.AddProjectStandardRequest;
import com.zbkj.common.response.UploadResponse;
import com.zbkj.common.response.project.*;
import com.zbkj.common.token.FrontTokenComponent;
import com.zbkj.common.utils.CommonUtil;
import com.zbkj.common.utils.FileUtil;
import com.zbkj.common.vo.project.ClientEstimateFunToExcelVo;
import com.zbkj.common.vo.project.ProjectModifyConditionVo;
import com.zbkj.common.vo.project.ProjectQueryVo;
import com.zbkj.common.vo.user.UserDatavalVo;
import com.zbkj.front.service.ProjectV2HandlerService;
import com.zbkj.service.service.SystemConfigService;
import com.zbkj.service.service.UploadService;
import com.zbkj.service.service.project.*;
import com.zbkj.service.service.standard.IPeProjectStandardService;
import com.zbkj.service.service.user.UserBillService;
import com.zbkj.service.service.user.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Auther:
 * @Date: 2024/9/12 15:42
 * @Description:
 */
@Slf4j
@Service
public class ProjectV2HandlerServiceImpl implements ProjectV2HandlerService {

    @Autowired
    private BaseConfig baseConfig;
    @Autowired
    @Lazy
    private ProjectV2HandlerService projectV2HandlerService;
    @Autowired
    private UploadService uploadService;
    @Autowired
    private UserService userService;
    @Autowired
    private FrontTokenComponent frontTokenComponent;
    @Autowired
    private ProjectInfoService projectInfoService;
    @Autowired
    private OssClientUtil ossClientUtil;
    @Autowired
    private ProjectInformationService projectInformationService;
    @Autowired
    private SystemConfigService systemConfigService;
    @Autowired
    private AireqTaskService aireqTaskService;
    @Autowired
    private EstimateFunService estimateFunService;
    @Autowired
    private EstimateInformationService estimateInformationService;
    @Autowired
    private UserBillService userBillService;
    @Autowired
    private CityWeightService cityWeightService;
    @Autowired
    private ProjectParamGuoService projectParamGuoService;
    @Autowired
    private ProjectParamJunService projectParamJunService;
    @Autowired
    private IPeAiWriteHistoryService peAiWriteHistoryService;

    @Autowired
    private IPeProjectStandardService peProjectStandardService;

    @Override
    public PageInfo<ClientProjectInfoResponse> projectList(ClientProjectQueryRequest queryRequest) {
        Long userId = frontTokenComponent.getLoginUserId();
        /*if(Objects.isNull(queryRequest.getQueryStatus())) {
            throw new CommonException("缺少项目状态查询参数");
        }*/
        ProjectQueryVo queryVo = new ProjectQueryVo();
        if(Objects.nonNull(queryRequest.getQueryStatus())) {
            queryVo.setStatusList(Lists.newArrayList(queryRequest.getQueryStatus()));
        }
        queryVo.setProjectName(queryRequest.getProjectName());
        queryVo.setUserId(userId);
        queryVo.setStatusSort(queryRequest.getQueryStatus());
        queryVo.setSource(1);
        queryVo.setProjectType(queryRequest.getProjectType());
        if(Objects.nonNull(queryRequest.getSourceType())) {
            queryVo.setSourceType(queryRequest.getSourceType());
            if(queryRequest.getSourceType().intValue() == 1) {
                //模板项目查询获取不需要带有用户ID
                queryVo.setUserId(null);
                //模板项目查询 只能查询估算完成之后状态的项目
                /*queryVo.setStatusList(Lists.newArrayList(ProjectStatusEnum.COMPLET_ESTIMATE.getStatus(),
                        ProjectStatusEnum.IN_REPORT.getStatus(),ProjectStatusEnum.FINISH.getStatus()));*/
            }
        }

        //分页查询项目列表
        PageInfo<ProjectInfo> projectPage = projectInfoService.projectList(queryVo,queryRequest.getPage(),queryRequest.getLimit());
        List<ClientProjectInfoResponse> responseList = Lists.newArrayList();
        for(ProjectInfo projectInfo : projectPage.getList()) {
            ClientProjectInfoResponse response = new ClientProjectInfoResponse();
            BeanUtils.copyProperties(projectInfo, response);
            //客户端项目信息显示字段值处理
            this.clientProjectShowSetting(projectInfo, response);
            if(response.getSourceType() == 1) {
                response.setDemoReportUrl("https://static.qccz.com.cn/快递管家PC端价格预估咨询报告-国标-审阅.pdf");
            }
            responseList.add(response);
        }
        return CommonPage.copyPageInfo(projectPage, responseList);
    }

    /**
     * 客户端项目信息显示字段值处理
     * @param projectInfo
     * @param response
     */
    private void clientProjectShowSetting(ProjectInfo projectInfo, ClientProjectInfoResponse response) {
        if(projectInfo.getEstimateFlag().intValue() != 1) {
            response.setSoftwarePoints(null);
            response.setSoftwareFee(null);
            response.setSoftwareFun(null);
        } else {
            /*if(projectInfo.getStatus().intValue() <= ProjectStatusEnum.IN_REPORT.getStatus() && projectInfo.getReportFlag() != 2) {
                response.setSoftwarePoints(projectInfo.getAisoftwarePoints());
                response.setSoftwareFun(projectInfo.getAisoftwareFun());
                response.setSoftwareFee(projectInfo.getAisoftwareFee());
            }*/
        }
    }

    private void clientProjectShowSetting(ProjectInfo projectInfo, EstimateRestProjectResponse response) {
        if(projectInfo.getEstimateFlag().intValue() != 1) {
            response.setSoftwarePoints(null);
            response.setSoftwareFee(null);
            response.setSoftwareFun(null);
        } else {
            /*if(projectInfo.getStatus().intValue() <= ProjectStatusEnum.IN_REPORT.getStatus() && projectInfo.getReportFlag() != 2) {
                response.setSoftwarePoints(projectInfo.getAisoftwarePoints());
                response.setSoftwareFun(projectInfo.getAisoftwareFun());
                response.setSoftwareFee(projectInfo.getAisoftwareFee());
            }*/
        }
    }
    @Override
    public UploadResponse informationUpload(Integer type, MultipartFile multipartFile) {
        if(!InformationTypEnum.clientTypeCheck(type)) {
            throw new CommonException("文件类型参数错误");
        }
        if(multipartFile == null || multipartFile.isEmpty()) {
            throw new CommonException("上传文件不能为空");
        }
        UploadResponse uploadResponse = new UploadResponse();
        uploadResponse.setFileName(multipartFile.getOriginalFilename());
        String fileType = FilenameUtils.getExtension(uploadResponse.getFileName());
        if(!CommonUtil.fileTypeCheck(Constants.CLIENT_FILE_TYPES,fileType)) {
            throw new CommonException("上传文件类型错误");
        }
        uploadResponse.setExtName(fileType);
        uploadResponse.setFileSize(multipartFile.getSize());
        String fileUrl =  uploadService.informationUpload(fileType, multipartFile);
        uploadResponse.setUrl(fileUrl);
        return uploadResponse;
    }

    @Override
    public void createProjectBak(ClientProjectRequest projectRequest) {
        //资料文件检查
        this.informationRequestCheck(projectRequest.getInformationRequestList());
        Date currentDate = new Date();
        User user = this.getUserCheckForProjectSave(currentDate);
        projectRequest.setId(null);
        //检查项目名称是否存在
        Integer nameRepeatNum = projectInfoService.projectNameRepeatCheck(user.getId(),projectRequest.getProjectName(),projectRequest.getId());
        if(nameRepeatNum > 0) {
            throw new CommonException("项目名称已存在");
        }
        ProjectInfo projectInfo = this.projectReqToPojo(projectRequest,user,currentDate);
        List<ProjectInformation> pinfList = this.informationReqToPojo(projectInfo, user, projectRequest.getInformationRequestList());
        ProjectParamGuo paramGuo = null;
        ProjectParamJun paramJun = null;
        if(projectRequest.getProjectType().intValue() == 1) {
            paramGuo = ProjectParamGuoRequest.paramGuoCheckAndToPojo(projectRequest.getParamGuoRequest());
        } else if(projectRequest.getProjectType().intValue() == 2) {
            paramJun = ProjectParamJunRequest.paramJunCheckAndToPojo(projectRequest.getParamJunRequest());
        }
        //项目保存前处理 项目文件解析获取字符数 | 设置设法自动进行ai估算请求
        prjectBeforSaveCheck(projectInfo, pinfList);
        //项目保存处理
        projectV2HandlerService.pojectSaveHandle(user, projectInfo,pinfList, paramGuo, paramJun);
    }
    @Override
    public void resubmitProject(ClientProjectRequest projectRequest) {
        //资料文件检查
        this.informationRequestCheck(projectRequest.getInformationRequestList());
        Date currentDate = new Date();
        User user = this.getUserCheckForProjectSave(currentDate);
        //获取项目信息-检查是否存在|是否登录用户创建
        ProjectInfo projectDb = this.getProjectAndCheck(projectRequest.getId(),user.getId());
        if(!(ProjectStatusEnum.isCompletEstimate(projectDb.getStatus()) || ProjectStatusEnum.isWithdrawn(projectDb.getStatus()))) {
            throw new CommonException("项目状态已变更，不能重新提交");
        }
        if(!StringUtils.equals(projectDb.getProjectName(),projectRequest.getProjectName())) {
            //检查项目名称是否存在
            Integer nameRepeatNum = projectInfoService.projectNameRepeatCheck(user.getId(),projectRequest.getProjectName(),projectRequest.getId());
            if(nameRepeatNum > 0) {
                throw new CommonException("项目名称已存在");
            }
        }
        ProjectInfo updateProject = this.projectReqToPojo(projectRequest,user,currentDate);
        updateProject.setId(projectDb.getId());
        updateProject.setStatus(ProjectStatusEnum.TO_ESTIMATE.getStatus());
        //重新提交-属性初始化
        projectInfoService.projectRestInit(updateProject);
        List<ProjectInformation> pinfList = this.informationReqToPojo(updateProject, user, projectRequest.getInformationRequestList());
        //项目保存前处理 项目文件解析获取字符数 | 设置设法自动进行ai估算请求
        prjectBeforSaveCheck(updateProject, pinfList);
        //项目保存处理
        projectV2HandlerService.pojectSaveHandle(user, updateProject,pinfList,null, null);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void pojectSaveHandle(User user, ProjectInfo projectInfo, List<ProjectInformation> informationList, ProjectParamGuo paramGuo, ProjectParamJun paramJun) {
//        Long usedCharNum = informationList.stream().filter(iv->Objects.nonNull(iv.getCharNum())).collect(Collectors.summingLong(v->v.getCharNum()));
//        usedCharNum = Objects.isNull(usedCharNum) ? 0 : usedCharNum;
//        long validCahrNum = user.getDataval() + user.getCardDataval();
//        log.info("用户可用流量包:{}-上传文件字符数:{}",validCahrNum,usedCharNum);
//        if(validCahrNum < usedCharNum) {
//            String msg = String.format("剩余流量不足已超出%s字符，请充值后重试",(usedCharNum-validCahrNum));
//            throw new ResultException(ExceptionCodeEnum.NEED_RECHARGE_ERROR.getCode(),msg);
//        }
        //自动发送ai估算-生成估算流水号
        projectInfo.setAireqNo(CommonUtil.getRandomStr(""));
        if(Objects.isNull(projectInfo.getId())) { //新增处理
            boolean flag = projectInfoService.save(projectInfo);
            if(!flag) {
                throw new CommonException("项目信息保存失败");
            }
            //调整因子保存
            if(projectInfo.getProjectType().intValue() == 1) {
                paramGuo.setProjectId(projectInfo.getId());
                projectParamGuoService.save(paramGuo);
            } else if(projectInfo.getProjectType().intValue() == 2) {
                paramJun.setProjectId(projectInfo.getId());
                projectParamJunService.save(paramJun);
            }
            for(ProjectInformation info : informationList) {
                info.setProjectId(projectInfo.getId());
            }
        } else { //更新处理
            ProjectModifyConditionVo conditionVo = new ProjectModifyConditionVo();
            conditionVo.setStatusList(Lists.newArrayList(ProjectStatusEnum.COMPLET_ESTIMATE.getStatus(),ProjectStatusEnum.WITHDRAWN.getStatus()));
            boolean updateFlag = projectInfoService.updateProject(projectInfo, conditionVo);
            if(!updateFlag) {
                throw new CommonException("项目信息已变更，请稍后重试");
            }
            //将当前有效资料更新为历史状态
            projectInformationService.updateStatusToHis(projectInfo.getId());
        }
        //批量保存项目文档
        projectInformationService.saveBatch(informationList,informationList.size());
        //项目进行扣费处理及记录账本处理
        this.projectPayHandle(user, projectInfo.getId(), projectInfo.getAireqNo());
        if(projectInfo.getEstimateSource().intValue() == 1) {
            aireqTaskService.initReqTest(projectInfo.getId(), projectInfo.getAireqNo());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void pojectSaveHandle(User user, ProjectInfo projectInfo, List<ProjectInformation> informationList, List<PeProjectStandard> projectStandardLs) {
        //自动发送ai估算-生成估算流水号
        projectInfo.setAireqNo(CommonUtil.getRandomStr(""));
        if(Objects.isNull(projectInfo.getId())) { //新增处理
            boolean flag = projectInfoService.save(projectInfo);
            if(!flag) {
                throw new CommonException("项目信息保存失败");
            }
            for(ProjectInformation info : informationList) {
                info.setProjectId(projectInfo.getId());
            }
            projectStandardLs.forEach(item -> item.setProjectId(projectInfo.getId()));
            peProjectStandardService.saveBatch(projectStandardLs);
        } else { //更新处理
            ProjectModifyConditionVo conditionVo = new ProjectModifyConditionVo();
            conditionVo.setStatusList(Lists.newArrayList(ProjectStatusEnum.COMPLET_ESTIMATE.getStatus(),ProjectStatusEnum.WITHDRAWN.getStatus()));
            boolean updateFlag = projectInfoService.updateProject(projectInfo, conditionVo);
            if(!updateFlag) {
                throw new CommonException("项目信息已变更，请稍后重试");
            }
            //将当前有效资料更新为历史状态
            projectInformationService.updateStatusToHis(projectInfo.getId());
            //项目使用的标准信息保存
            projectStandardLs.forEach(item -> item.setProjectId(projectInfo.getId()));
            peProjectStandardService.deleteByProjectId(projectInfo.getId());
            peProjectStandardService.saveBatch(projectStandardLs);
        }
        //批量保存项目文档
        projectInformationService.saveBatch(informationList,informationList.size());
        //项目进行扣费处理及记录账本处理
        this.projectPayHandle(user, projectInfo.getId(), projectInfo.getAireqNo());
        if(projectInfo.getEstimateSource().intValue() == 1) {
            aireqTaskService.initReqTest(projectInfo.getId(), projectInfo.getAireqNo());
        }
    }

    @Override
    public ClientProjectInfoResponse getProjectInfo(Long projectId) {
        Long userId = frontTokenComponent.getLoginUserId();
        //获取项目信息-检查是否存在|是否登录用户创建
        ProjectInfo projectDb = this.getProjectAndCheck(projectId,userId, 1);
        ClientProjectInfoResponse  response = new ClientProjectInfoResponse();
        BeanUtils.copyProperties(projectDb,response);
        //客户端项目信息显示字段值处理
        this.clientProjectShowSetting(projectDb, response);
        //调整因子参数信息
        ProjectParamResponse projectParam = getProjectParam(projectDb.getId(),projectDb.getProjectType(),0);
        response.setProjectParam(projectParam);
        //获取当前有效的项目资料文件列表
        List<ProjectInformation> dbList = projectInformationService.getValidProjectInformationList(projectId);
        List<InformationResponse> fileResponseList = Lists.newArrayList();
        for(ProjectInformation pojo : dbList) {
            InformationResponse vo = new InformationResponse();
            BeanUtils.copyProperties(pojo, vo);
            vo.setFilePath(ossClientUtil.addDomain(vo.getFilePath()));
            fileResponseList.add(vo);
        }
        response.setInformationResponseList(fileResponseList);
        return response;
    }

    @Override
    public void delProject(Long projectId) {
        Long userId = frontTokenComponent.getLoginUserId();
        //获取项目信息-检查是否存在|是否登录用户创建
        ProjectInfo projectDb = this.getProjectAndCheck(projectId,userId);
        if(!ProjectStatusEnum.isToEstimate(projectDb.getStatus())) {
            throw new CommonException("项目状态已变更，不能删除");
        }
        ProjectInfo updateProject = new ProjectInfo();
        updateProject.setId(projectDb.getId());
        updateProject.setDeleteFlag(1);
        ProjectModifyConditionVo conditionVo = new ProjectModifyConditionVo();
        conditionVo.setStatusList(Lists.newArrayList(ProjectStatusEnum.TO_ESTIMATE.getStatus()));
        boolean updateFlag = projectInfoService.updateProject(updateProject, conditionVo);
        if(!updateFlag) {
            throw new CommonException("项目信息已变更，删除操作失败");
        }
    }

    @Override
    public EstimateRestProjectResponse getEstimateResult(Long projectId) {
        Long userId = frontTokenComponent.getLoginUserId();
        ProjectInfo projectInfo = this.getProjectAndCheck(projectId, userId, 1);
        EstimateRestProjectResponse restResponse = new EstimateRestProjectResponse();
        BeanUtils.copyProperties(projectInfo,restResponse);
        restResponse.setProjectId(projectInfo.getId());
        //军标项目信息配置重用程度选项对应系数
        restResponse.setReuseVal(ProjectFunItem1Enum.findItemVal(projectInfo.getProjectType(),projectInfo.getReuseItem()));
        //人月费用
        restResponse.setPerMonthFee(cityWeightService.getPerMonthFee(projectInfo.getProjectType(),projectInfo.getCityCode()));
        this.clientProjectShowSetting(projectInfo, restResponse);

        //获取调整因子参数
        int queryType = (projectInfo.getReportFlag() != 2) ? 0 : 2;
        ProjectParamResponse paramResponse = this.getProjectParam(projectInfo.getId(),projectInfo.getProjectType(),queryType);
        restResponse.setProjectParam(paramResponse);
        List<EstimateFunDetailResponse> restFunList = Lists.newArrayList();
        if(projectInfo.getEstimateFlag() == 1) {
            List<EstimateFun> estimateFunList = estimateFunService.getValidFunDetailList(projectInfo.getId(),3, projectInfo.getAireqNo());
            int showMax = estimateFunList.size();
            if(projectInfo.getReportFlag() != 2) {
                showMax = showMax<10 ? showMax : (showMax >= 30 ? 15 : showMax/3);
            }
            for(int i=0; i<showMax; i++) {
                EstimateFun fun = estimateFunList.get(i);
                EstimateFunDetailResponse temFunResp = new EstimateFunDetailResponse();
                BeanUtils.copyProperties(fun,temFunResp);
                restFunList.add(temFunResp);
            }
        }
        restResponse.setFunDetailList(restFunList);
        return restResponse;
    }

    @Override
    public void reportApply(Long projectId) {
        Long userId = frontTokenComponent.getLoginUserId();
        ProjectInfo projectDb = this.getProjectAndCheck(projectId, userId);
        if(!ProjectStatusEnum.isCompletEstimate(projectDb.getStatus())) {
            throw new CommonException("项目信息已变更，请稍后再试");
        }
        if(!ReportApplyStatusEnum.applyStatusCheck(projectDb.getReportApplyStatus())) {
            throw new CommonException("项目报告正在处理中,请耐心等待");
        }
        ProjectInfo updateProject = new ProjectInfo();
        updateProject.setId(projectDb.getId());
        updateProject.setReportApplyStatus(ReportApplyStatusEnum.IN_APPLY.getStatus());
        ProjectModifyConditionVo conditionVo = new ProjectModifyConditionVo();
        //设置更新检查条件
        conditionVo.setStatusList(Lists.newArrayList(ProjectStatusEnum.COMPLET_ESTIMATE.getStatus()));
        //报告申请状态检查条件
        conditionVo.setReportApplyStatusList(ReportApplyStatusEnum.applyCheckStatusList());
        boolean updateFlag = projectInfoService.updateProject(updateProject, conditionVo);
        if(!updateFlag) {
            throw new CommonException("项目信息已变更，请稍后再试");
        }
    }

    @Override
    public void estimateFileDownload(ClientProjectDownloadRequest downloadRequest, HttpServletResponse response) {
        Long projectId = downloadRequest.getProjectId();
        if(!InformationTypEnum.clientDownloadTypeCheck(downloadRequest.getFileType())) {
            throw new CommonException("下载文件类型错误");
        }
        Long userId = frontTokenComponent.getLoginUserId();
        //获取项目信息-检查是否存在|是否登录用户创建
        ProjectInfo projectDb = this.getProjectAndCheck(projectId, userId, 1);
        if(projectDb.getReportFlag().intValue() != 2) {
            //下载报告文件时判断是否已上传报告
            throw new CommonException("文件还未生成，请稍后再试");
        }
        Integer status = Objects.isNull(downloadRequest.getFileId()) ? null : CommonStatusEnum.VALID_STATUS.getStatus();
        EstimateInformation information = estimateInformationService.getOneRecord(downloadRequest.getFileId(),projectId, downloadRequest.getFileType(),status);
        if(Objects.isNull(information) || StringUtils.isBlank(information.getFilePath())) {
            throw new CommonException("文件还未生成，请稍后再试");
        }
        //文件路径增加oss内网访问域名
        String netPath = ossClientUtil.addInnerDomain(information.getFilePath());
        String originalFileName = information.getFileName();
        InputStream redIn = null;
        ServletOutputStream outputStream = null;
        try{
            URL netUrl = new URL(netPath);
            redIn = netUrl.openConnection().getInputStream();
            response.setContentType("application/octet-stream");
            response.addHeader("Access-Control-Expose-Headers","Content-Disposition,File-Type");
            response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(originalFileName, "UTF-8"));
            String fileType = FilenameUtils.getExtension(originalFileName);
            response.addHeader("File-Type",fileType);
            outputStream = response.getOutputStream(); //字节流
            byte[] bytes = new byte[1024*10];
            int read;
            do {
                read = redIn.read(bytes);
                outputStream.write(bytes,0,read);
            }while (-1 != read);
            outputStream.flush();
        } catch (Exception e) {
            log.error("项目资料下载异常-projectId:{}-fileId{}-error:",projectId,information.getId(),e);
            throw new CommonException("读取文件失败，请稍后再试");
        } finally {
            IOUtils.closeQuietly(redIn);
            IOUtils.closeQuietly(outputStream);
        }
    }

    @Override
    public void estimateFunFileDownload(Long projectId, HttpServletResponse response) {
        Long userId = frontTokenComponent.getLoginUserId();
        boolean yearUserFlag = userService.getYearUserFlag(userId);
        if(!yearUserFlag){
            throw new CommonException("目前该功能仅对正式会员开放，如有需要，请购买正式会员，感谢您的理解与支持！");
        }
        //获取项目信息-检查是否存在|是否登录用户创建
        ProjectInfo projectInfo = this.getProjectAndCheck(projectId, userId, 1);
        if(!ProjectStatusEnum.isFinish(projectInfo.getStatus())) {
            throw new CommonException("报告未完成，功能点明细无法导出下载");
        }
        //获取编辑后的功能点明细list
        List<EstimateFun> estimateFunList = estimateFunService.getValidFunDetailList(projectId,3, projectInfo.getAireqNo());
        if(CollectionUtils.isEmpty(estimateFunList)) {
            throw new CommonException("功能点明细还未生成，请稍后再试");
        }
        File funFile = estimateFunWiteToExcel(estimateFunList);
        if(Objects.isNull(funFile) || !funFile.exists()) {
            throw new CommonException("功能点明细导出文件失败，请稍后再试");
        }

        // todo wjh 添加测算明细
        try(InputStream in = new FileInputStream(funFile);
            OutputStream outputStream = response.getOutputStream();){
            String originalFileName = "功能点明细.xlsx";
            response.setContentType("application/octet-stream");
            response.addHeader("Access-Control-Expose-Headers","Content-Disposition,File-Type");
            response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(originalFileName, "UTF-8"));
            String fileType = FilenameUtils.getExtension(originalFileName);
            response.addHeader("File-Type",fileType);
            byte[] bytes = new byte[1024*10];
            int read;
            do {
                read = in.read(bytes);
                outputStream.write(bytes,0,read);
            }while (-1 != read);
            outputStream.flush();
        } catch (Exception e) {
            log.error("功能点明细下载异常-projectId:{}-error:",projectId,e);
            throw new CommonException("功能点明细导出文件异常，请稍后再试");
        } finally {
            if(funFile.exists()) {
                funFile.delete();
            }
        }
    }


    private void informationRequestCheck(List<ClientInformationRequest> informationRequestList) {
        ClientInformationRequest fileRequest = informationRequestList.stream().
                filter(v->StringUtils.isBlank(v.getFilePath()))
                .findFirst().orElse(null);
        if(Objects.nonNull(fileRequest)) {
            throw new CommonException("请上传项目文件");
        }
    }

    private User getUserCheckForProjectSave(Date currentDate) {
        Long userId = frontTokenComponent.getLoginUserId();
        User user = userService.getUserById(userId);
        if(Objects.isNull(user) || user.getDeleteFlag() == 1) {
            throw new CommonException("账户已不存在");
        }
        if(user.getStatus() != 0) {
            throw new CommonException("账号已被禁用");
        }
        /*if(user.getAuthStatus() != 1) {
            throw new CommonException("未实名认证，请先进行实名认证");
        }*/
        if(Objects.isNull(user.getCardExpire()) || user.getCardExpire().getTime() < currentDate.getTime()) {
            throw new ResultException(ExceptionCodeEnum.NEED_RECHARGE_ERROR.getCode(),"请先购买会员包");
        }
//        long validDataVal = user.getCardDataval() + user.getDataval();
//        if(validDataVal <= 0) {
//            throw new CommonException("剩余流量已为0，请先进行充值");
//        }
        return user;
    }

    /**
     * 项目信息请求对象转换为pojo
     * @param projectRequest
     * @param user
     * @return
     */
    private ProjectInfo projectReqToPojo(ClientProjectRequest projectRequest, User user, Date currentDate) {
        ProjectInfo projectInfo = new ProjectInfo();
        BeanUtils.copyProperties(projectRequest,projectInfo);
        projectInfo.setUserId(user.getId());
        projectInfo.setCompanyName(user.getCompanyName());
        projectInfo.setCreateTime(currentDate);
        return projectInfo;
    }

    /**
     * 资料请求对象转为pojo
     * @param projectInfo
     * @param user
     * @param informationRequestList
     * @return
     */
    private List<ProjectInformation> informationReqToPojo(ProjectInfo projectInfo, User user,List<ClientInformationRequest> informationRequestList) {
        List<ProjectInformation> pinfList = Lists.newArrayList();
        //获取当前文件批次号
        String  batchNo = CommonUtil.getRandomStr("");
        for (ClientInformationRequest infReq : informationRequestList) {
            ProjectInformation projectIfomation = new ProjectInformation();
            BeanUtils.copyProperties(infReq,projectIfomation);
            projectIfomation.setProjectId(projectInfo.getId());
            projectIfomation.setBatchNo(batchNo);
            projectIfomation.setCreateId(user.getId());
            projectIfomation.setCreateName(user.getRealName());
            projectIfomation.setFilePath(ossClientUtil.clearDomain(infReq.getFilePath()));
            pinfList.add(projectIfomation);
        }
        return pinfList;
    }

    /**
     * 项目保存前处理 项目文件解析获取字符数 | 设置设法自动进行ai估算请求
     * @param projectInfo
     * @param informationList
     */
    private void prjectBeforSaveCheck(ProjectInfo projectInfo, List<ProjectInformation> informationList) {
        if(projectInfo.getProjectType().intValue() == 1) {
            if(StringUtils.isBlank(projectInfo.getProvinceCode()) || StringUtils.isBlank(projectInfo.getProvinceName())
                    || StringUtils.isBlank(projectInfo.getCityCode()) || StringUtils.isBlank(projectInfo.getCityName())) {
                throw new CommonException("请选择省份城市");
            }
            projectInfo.setReuseItem(0);//国标赋值0
        } else {
            //军标检查重用程度值
            if(!ProjectFunItem1Enum.itemCheck(projectInfo.getProjectType(),projectInfo.getReuseItem())) {
                throw new CommonException("重用程度参数错误");
            }
        }
        projectInfo.setEstimateSource(1);
        String aiCharLimitCfgStr = systemConfigService.getValueByKey(Constants.AI_ESTIAM_CONTENT_LIMIT_CFG);
        long aiCharLimitCfg = StringUtils.isBlank(aiCharLimitCfgStr) ? -1 : Long.valueOf(aiCharLimitCfgStr);
        String tmpPathPrefix = String.format("%s%s/", baseConfig.getImagePath(),Constants.PROJECT_DOC_PREFIX);
        long totalCharNum = 0;
        for (ProjectInformation information : informationList) {
            long tmpCharNum = FileUtil.readNetWordCharCount(ossClientUtil.addInnerDomain(information.getFilePath()),information.getFileName(),tmpPathPrefix);
            if(tmpCharNum <= 0) {
                throw new CommonException(String.format("%s文件为空文档",information.getFileName()));
            }
            information.setCharNum(tmpCharNum);
            totalCharNum += tmpCharNum;
            if(aiCharLimitCfg >= 0 && aiCharLimitCfg < tmpCharNum) {
                projectInfo.setEstimateSource(3);
            }
        }

        projectInfo.setTotalCharum(totalCharNum);
        String aiAutoSwitch = systemConfigService.getValueByKey(Constants.AI_ESTIAM_AUTO_SWITCH_CFG);
        if(!"0".equals(aiAutoSwitch)) {
            projectInfo.setEstimateSource(2);
        }
    }

    private void projectPayHandle(User user, Long sourceId, String aireqNo) {
        long usedDataval = 0; //流量包使用数
        long useCardDataval = 0; //订阅包使用数
//        if(user.getCardDataval().longValue() < usedCharNum) {
//            usedDataval = usedCharNum - user.getCardDataval();
//            useCardDataval = user.getCardDataval();
//        } else {
//            useCardDataval = usedCharNum;
//        }
        UserDatavalVo userDatavalVo = new UserDatavalVo();
        userDatavalVo.setUserId(user.getId());
        userDatavalVo.setCardDataval(useCardDataval);
        userDatavalVo.setDataval(usedDataval);
        userDatavalVo.setYearPid(useCardDataval>0?user.getCardId():null);
        userDatavalVo.setPmtype(0);
        userDatavalVo.setCategoryEnum(UserBillCategoryEnum.BILL_CATEGORY2);
        userDatavalVo.setSourceType(2);
        userDatavalVo.setSourceId(sourceId);
        userDatavalVo.setSourceNo(aireqNo);
        //组装用户账本
        List<UserBill> userBillList =  userBillService.userDataValVoToPojo(userDatavalVo);
        boolean updateFlag = userService.deductDataval(userDatavalVo,userBillList);
        if(!updateFlag) {
            throw new CommonException("用户扣流量失败");
        }
    }

    /**
     * 获取项目信息-检查是否存在|是否登录用户创建
     * @param projectId
     * @param userId
     * @return
     */
    public ProjectInfo getProjectAndCheck(Long projectId, Long userId) {
        ProjectInfo projectDb = projectInfoService.getById(projectId);
        if(Objects.isNull(projectDb) || projectDb.getDeleteFlag() != 0) {
            throw new CommonException("项目信息已不存在");
        }
        if(projectDb.getUserId().longValue() != userId.longValue()) {
            throw new CommonException("无权限操作该项目");
        }
        return projectDb;
    }

    @Override
    public boolean submitDelivery(Long projectId, ProjectDeliveryRequest queryRequest) {
        Long userId = frontTokenComponent.getLoginUserId();
        //获取项目信息-检查是否存在|是否登录用户创建
        this.getProjectAndCheck(projectId,userId);
        ProjectInfo projectInfo = new ProjectInfo();
        BeanUtils.copyProperties(queryRequest,projectInfo);
        projectInfo.setId(projectId);
        return projectInfoService.updateById(projectInfo);
    }

    @Override
    public DeliveryInfoResponse getDeliveryInfo(Long projectId) {
        ProjectInfo projectDb = projectInfoService.getById(projectId);
        DeliveryInfoResponse deliveryInfoResponse = new DeliveryInfoResponse();
        BeanUtils.copyProperties(projectDb, deliveryInfoResponse);
        return deliveryInfoResponse;
    }

    /**
     * 检查项目及创建者
     * @param projectId
     * @param userId
     * @param fiterSourceType  0 客户项目  1 模板项目 （不进行用户检查）
     * @return
     */
    private ProjectInfo getProjectAndCheck(Long projectId, Long userId, int fiterSourceType) {
        ProjectInfo projectDb = projectInfoService.getById(projectId);
        if(Objects.isNull(projectDb) || projectDb.getDeleteFlag() != 0) {
            throw new CommonException("项目信息已不存在");
        }
        if(projectDb.getSourceType() != fiterSourceType
                && projectDb.getUserId().longValue() != userId.longValue()) {
            throw new CommonException("无权限操作该项目");
        }
        return projectDb;
    }

    /**
     * 获取项目调整因子参数
     * @param projectId
     * @param projectType
     * @param queryType
     * @return
     */
    private ProjectParamResponse getProjectParam(Long projectId, Integer projectType, int queryType) {
        ProjectParamResponse paramResponse = new ProjectParamResponse();
        if(Objects.isNull(projectId) || Objects.isNull(projectType)) {
            return paramResponse;
        }
        if(projectType == 1) {
            ProjectParamGuo pojo = projectParamGuoService.getParamGouByQueryType(queryType,projectId);
            if(Objects.nonNull(pojo)) {
                ProjectParamGuoResponse response = new ProjectParamGuoResponse();
                BeanUtils.copyProperties(pojo,response);
                paramResponse.setParamGuoResponse(response);
            }
        } else if(projectType == 2) {
            ProjectParamJun pojo = projectParamJunService.getParamJunByQueryType(queryType,projectId);
            if(Objects.nonNull(pojo)) {
                ProjectParamJunResponse response = new ProjectParamJunResponse();
                BeanUtils.copyProperties(pojo,response);
                paramResponse.setParamJunResponse(response);
            }
        }
        return paramResponse;
    }

    private File estimateFunWiteToExcel(List<EstimateFun> estimateFunList) {
        List<ClientEstimateFunToExcelVo> funToExcelVoList = Lists.newArrayList();
        for (EstimateFun estimateFun : estimateFunList) {
            ClientEstimateFunToExcelVo funToExcelVo = new ClientEstimateFunToExcelVo();
            BeanUtils.copyProperties(estimateFun,funToExcelVo);
            //重用程度-选项名称
            funToExcelVo.setItme1Str(ProjectFunItem1Enum.getItemName(estimateFun.getItme1()));
            //修改类型-选项名称
            funToExcelVo.setItme2Str(ProjectFunItem2Enum.getItemName(estimateFun.getItme2()));
            funToExcelVoList.add(funToExcelVo);
        }
        String tempFilePath = baseConfig.getLocalTempFilePath(Constants.PROJECT_DOC_PREFIX,".xlsx");
        File localFile = new File(tempFilePath);
        FileUtil.dirCreate(localFile.getParentFile());
        EasyExcel.write(localFile, ClientEstimateFunToExcelVo.class)
                .sheet()
                .doWrite(() -> {return funToExcelVoList;});
        return localFile;
    }



    @Override
    public void submitAIHistory() {
        Long userId = frontTokenComponent.getLoginUserId();
        PeAiWriteHistory peAiWriteHistory = new PeAiWriteHistory();
        peAiWriteHistory.setUserId(userId);
        peAiWriteHistory.setCreateTime(new Date());
        peAiWriteHistoryService.save(peAiWriteHistory);
    }

    @Override
    public AiReportResponse aiReport(ReportRequest reportRequest) {
        List<PeAiWriteHistory> peAiWriteHistories = peAiWriteHistoryService.queryByTime(reportRequest.getStartDate(), reportRequest.getEndDate());
        AiReportResponse  aiReportResponse = new AiReportResponse();
        if(ObjectUtils.isNotEmpty(peAiWriteHistories)){
            aiReportResponse.setAiWriteCount(peAiWriteHistories.size());
            aiReportResponse.setAiWritePeopleCount((int) peAiWriteHistories.stream().map(PeAiWriteHistory::getUserId).distinct().count());
        }
        return aiReportResponse;
    }

    @Override
    public void createProject(ClientProjectRequest projectRequest) {
        //资料文件检查
        this.informationRequestCheck(projectRequest.getInformationRequestList());
        Date currentDate = new Date();
        User user = this.getUserCheckForProjectSave(currentDate);
        projectRequest.setId(null);
        //检查项目名称是否存在
        Integer nameRepeatNum = projectInfoService.projectNameRepeatCheck(user.getId(),projectRequest.getProjectName(),projectRequest.getId());
        if(nameRepeatNum > 0) {
            throw new CommonException("项目名称已存在");
        }
        ProjectInfo projectInfo = this.projectReqToPojo(projectRequest,user,currentDate);
        List<ProjectInformation> pinfList = this.informationReqToPojo(projectInfo, user, projectRequest.getInformationRequestList());
        List<PeProjectStandard> projectStandardLs = this.projectStandardReqToPojo(projectRequest.getAddProjectStandardRequestList());
        //项目保存前处理 项目文件解析获取字符数 | 设置设法自动进行ai估算请求
        prjectBeforSaveCheck(projectInfo, pinfList);
        //项目保存处理
        projectV2HandlerService.pojectSaveHandle(user, projectInfo,pinfList, projectStandardLs);
    }

    @Override
    public List<PeProjectStandard> projectStandardReqToPojo(List<AddProjectStandardRequest> addProjectStandardRequestList) {
        List<PeProjectStandard> list = new ArrayList<>();
        addProjectStandardRequestList.forEach(addProjectStandardRequest -> {
            PeProjectStandard peProjectStandard = new PeProjectStandard();
            BeanUtils.copyProperties(addProjectStandardRequest, peProjectStandard);
            list.add(peProjectStandard);
        });
        return list;
    }

    @Override
    public List<ProjectTypeStatisticsResponse> projectTypeStatistics(Long projectId) {
        List<EstimateFun> list = estimateFunService.getListByProjectId(projectId);
        if(ObjectUtil.isEmpty(list)){
            return null;
        }
        Map<String, Long> funTypeMap = list.stream().collect(Collectors.groupingBy(EstimateFun::getFunType, Collectors.counting()));
        List<ProjectTypeStatisticsResponse> responseList = new ArrayList<>();
        funTypeMap.forEach((key, value) -> {
            ProjectTypeStatisticsResponse response = new ProjectTypeStatisticsResponse();
            response.setFunType(key);
            response.setCount(value.intValue());
            responseList.add(response);
        });
        return responseList;
    }
}
